home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
PC World Interactive 7
/
PC World Interactive 7.iso
/
program
/
ctutor.exe
/
TEXT
/
CHAP10.TXT
< prev
next >
Wrap
Text File
|
1994-05-15
|
19KB
|
406 lines
Chapter 10
FILE INPUT/OUTPUT
OUTPUT TO A FILE
-----------------------------------------------------------------
Load and display the file named FORMOUT.C for =================
your first example of writing data to a file. FORMOUT.C
We begin as before with the include statement =================
for STDIO.H, and include the header for the
string functions. Then we define some variables for use in the
example including a rather strange looking new type.
The type FILE is used for a file variable and is defined in the
STDIO.H file. It is used to define a file pointer for use in
file operations. The definition of C requires a pointer to a
FILE type to access a file, and as usual, the name can be any
valid variable name. Many writers use fp for the name of this
first example file pointer so I suppose we should start with
it too.
OPENING A FILE
-----------------------------------------------------------------
Before we can write to a file, we must open it. What this really
means is that we must tell the system that we want to write to a
file and what the filename is. We do this with the fopen()
function illustrated in line 11 of the program. The file
pointer, fp in our case, points to the file and two arguments
are required in the parentheses, the filename first, followed by
the file attribute. The filename is any valid DOS filename, and
can be expressed in upper or lower case letters, or even mixed if
you so desire. It is enclosed in double quotes. For this
example we have chosen the name TENLINES.TXT. This file should
not exist on your disk at this time. If you have a file with
this name, you should change its name or move it because when we
execute this program, its contents will be erased. If you don't
have a file by this name, this program will create one and put
some data into it.
Note that we are not forced to use a string constant for the file
name as we have done here. This is only done here for
convenience. We can use a string variable which contains the
filename then use any method we wish to fill in the name of the
file to open. This will be illustrated later in this chapter.
READING ("r")
-----------------------------------------------------------------
The second parameter is the file attribute and can be any of
three letters, "r", "w", or "a", and must be lower case. There
are actually additional attributes available in C to allow more
Page 10-1
Chapter 10 - File Input/Output
flexible I/O, and after you complete your study of this chapter,
you should check the documentation for your compiler to study the
additional file opening attributes. When an "r" is used, the
file is opened for reading, a "w" is used to indicate a file to
be used for writing, and an "a" indicates that you desire to
append additional data to the data already in an existing file.
Opening a file for reading requires that the file already exist.
If it does not exist, the file pointer will be set to NULL and
can be checked by the program. It is not checked in this
program, but could be easily checked as follows.
if (fp == NULL) {
printf("File failed to open\n");
exit;
}
Good programming practice would dictate that all file pointers be
checked to assure proper file opening in a manner similar to the
above code.
WRITING ("w")
-----------------------------------------------------------------
When a file is opened for writing, it will be created if it does
not already exist and it will be reset if it does resulting in
deletion of any data already there. If the file fails to open
for any reason, a NULL will be returned so the pointer should be
tested as above.
APPENDING ("a")
-----------------------------------------------------------------
When a file is opened for appending, it will be created if it
does not already exist and it will be initially empty. If it
does exist, the data input point will be the end of the present
data so that any new data will be added to any data that already
exists in the file. Once again, the return value can and should
be checked for proper opening.
OUTPUTTING TO THE FILE
-----------------------------------------------------------------
The job of actually outputting to the file is nearly identical to
the outputting we have already done to the standard output
device. The only real differences are the new function names and
the addition of the file pointer as one of the function
arguments. In the example program, fprintf() replaces our
familiar printf() function name, and the file pointer defined
earlier is the first argument within the parentheses. The
remainder of the statement looks like, and in fact is identical
to, the printf() statement.
Page 10-2
Chapter 10 - File Input/Output
CLOSING A FILE
-----------------------------------------------------------------
To close a file, use the function fclose() with the file pointer
in the parentheses. Actually, in this simple program, it is not
necessary to close the file because the system will close all
open files before returning to DOS. It would be good
programming practice for you to get in the habit of closing all
files in spite of the fact that they will be closed
automatically, because that would act as a reminder to you of
what files are open at the end of each program.
You can open a file for writing, close it, and reopen it for
reading, then close it, and open it again for appending, etc.
Each time you open it, you could use the same file pointer, or
you could use a different one. The file pointer is simply a tool
that you use to point to a file and you decide what file it will
point to.
Compile and run this program. When you run it, you will not get
any output to the monitor because it doesn't generate any. After
running it, look at your directory for a file named TENLINES.TXT
and examine it's contents. That is where your output will be.
Compare the output with that specified in the program. It should
agree. If you add the pointer test code described above, and if
the file couldn't be opened for any reason, there will be one
line of text on the monitor instead of the file listing.
Do not erase the file named TENLINES.TXT yet. We will use it in
some of the other examples in this chapter.
OUTPUTTING A SINGLE CHARACTER AT A TIME
-----------------------------------------------------------------
Load the next example file, CHAROUT.C, and ===============
display it on your monitor. This program will CHAROUT.C
illustrate how to output a single character at ===============
a time.
The program begins with the include statement, then defines some
variables including a file pointer. The file pointer is named
point this time, but we could have used any other valid variable
name. We then define a string of characters to use in the output
function using a strcpy() function. We are ready to open the
file for appending and we do so with the fopen() function, except
this time we use the lower cases for the filename. This is done
simply to illustrate that DOS doesn't care about the case of the
filename. Notice that the file will be opened for appending so
we will add to the lines inserted during the last program.
The program is actually two nested for loops. The outer loop is
simply a count to ten so that we will go through the inner loop
ten times. The inner loop calls the function putc() repeatedly
Page 10-3
Chapter 10 - File Input/Output
until a character in the string named others is detected to be a
zero. This is the terminating NULL for the string.
THE putc() FUNCTION
-----------------------------------------------------------------
The part of the program we are interested in is the putc()
function in line 16. It outputs one character at a time, the
character being the first argument in the parentheses and the
file pointer being the second and last argument. Why the
designer of C made the pointer first in the fprintf() function,
and last in the putc() function is a good question for which
there may be no answer. It seems like this would have been a
good place to have used some consistency.
When the textline others is exhausted, a newline is needed
because a newline was not included in the definition above. A
single putc() is then executed which outputs the \n character to
return the carriage and do a linefeed.
When the outer loop has been executed ten times, the program
closes the file and terminates. Compile and run this program but
once again there will be no output to the monitor.
Following execution of the program, examine the contents of the
file named TENLINES.TXT and you will see that the 10 new lines
were added to the end of the 10 that already existed. If you run
it again, yet another 10 lines will be added. Once again, do not
erase this file because we are still not finished with it.
READING A FILE
-----------------------------------------------------------------
Load the file named READCHAR.C and display it ================
on your monitor. This is our first program READCHAR.C
which can read from a file. This program ================
begins with the familiar include, some data
definitions, and the file opening statement which should require
no explanation except for the fact that an "r" is used here
because we want to read from this file. In this program, we
check to see that the file exists, and if it does, we execute the
main body of the program. If it doesn't exist, we print a
message and quit. If the file does not exist, the system will
set the pointer equal to NULL which we test in line 11. If the
pointer is NULL we display a message and terminate the program.
The main body of the program is one do while loop in which a
single character is read from the file and output to the monitor
until an EOF (end of file) is detected from the input file. The
file is then closed and the program is terminated.
Page 10-4
Chapter 10 - File Input/Output
CAUTION CAUTION CAUTION
-----------------------------------------------------------------
At this point, we have the potential for one of the most common
and most perplexing problems of programming in C. The variable
returned from the getc() function is a character, so we can use a
char variable for this purpose. There is a problem that could
develop here if we happened to use an unsigned char however,
because C returns a minus one for an EOF. An unsigned char type
variable is not capable of containing a negative value. An
unsigned char type variable can only have the values of zero to
255, so it will return a 255 for a minus one. This is a very
frustrating problem to try to find. The program can never find
the EOF and will therefore never terminate the loop. This is
easy to prevent, always use a char type variable for use in
returning an EOF.
There is another problem with this program but we will worry
about it when we get to the next program and solve it with the
one following that.
After you compile and run this program and are satisfied with the
results, it would be a good exercise to change the name of
TENLINES.TXT and run the program again to see that the NULL test
actually works as stated. Be sure to change the name back
because we are still not finished with TENLINES.TXT. In a real
production program, you would not actually terminate the program.
You would give the user the opportunity to enter another filename
for input. We are interested in illustrating the basic file
handling techniques here, so we are using a very simple error
handling method.
READING A WORD AT A TIME
-----------------------------------------------------------------
Load and display the file named READTEXT.C for ================
an example of how to read a word at a time. READTEXT.C
This program is nearly identical to the last ================
except that this program uses the fscanf()
function to read in a string at a time. Because the fscanf()
function stops reading when it finds a space or a newline
character, it will read a word at a time, and display the results
one word to a line. You will see this when you compile and run
it, but first we must examine a programming problem.
THIS IS A PROBLEM
-----------------------------------------------------------------
Inspection of the program will reveal that when we read data in
and detect the EOF, we print out something before we check for
the EOF resulting in an extra line of printout. What we usually
print out is the same thing printed on the prior pass through the
loop because it is still in the buffer named oneword. We
therefore must check for EOF before we execute the printf()
Page 10-5
Chapter 10 - File Input/Output
function. This has been done in READGOOD.C, which you will
shortly examine, compile, and execute.
Compile and execute the original program we have been studying,
READTEXT.C and observe the output. If you haven't changed
TENLINES.TXT you will end up with "Additional" and "lines." on
two separate lines with an extra "lines." displayed at the end of
the output because of the printf() before checking for EOF. Note
that some compilers apparently clear the buffer after printing so
you may get an extra blank line instead of two lines with
"lines." on them.
NOW LET'S FIX THE PROBLEM
-----------------------------------------------------------------
Compile and execute READGOOD.C and observe that ================
the extra "lines." does not get displayed READGOOD.C
because of the extra check for the EOF in the ================
middle of the loop. This was also the problem
referred to when we looked at READCHAR.C, but I chose not to
expound on it there because the error in the output was not so
obvious.
FINALLY, WE READ A FULL LINE
-----------------------------------------------------------------
Load and display the file READLINE.C for an ================
example of reading a complete line. This READLINE.C
program is very similar to those we have been ================
studying except that we read a complete line
in this example program.
We are using fgets() which reads an entire line, including the
newline character, into a buffer. The buffer to be read into is
the first argument in the function call, and the maximum number
of characters to read is the second argument, followed by the
file pointer. This function will read characters into the input
buffer until it either finds a newline character, or it reads the
maximum number of characters allowed minus one. It leaves one
character for the end of string NULL character. In addition, if
it finds an EOF, it will return a value of NULL. In our example,
when the EOF is found, the pointer named c will be assigned the
value of NULL. NULL is defined as zero in your STDIO.H file.
When we find that the pointer named c has been assigned the value
of NULL, we can stop processing data, but we must check before we
print just like in the last program. Last of course, we close
the file.
You can add a check for the file pointer being NULL for each of
these programs if you desire. In a production program, all
returned file pointers should be checked.
Page 10-6
Chapter 10 - File Input/Output
HOW TO USE A VARIABLE FILENAME
-----------------------------------------------------------------
Load and display the program ANYFILE.C for an =================
example of reading from any file. This ANYFILE.C
program asks the user for the filename =================
desired, and reads in the filename, storing
it in a string. Then it opens that file for reading. The entire
file is then read and displayed on the monitor. It should pose
no problems to your understanding so no additional comments will
be made.
Compile and run this program. When it requests a filename, enter
the name and extension of any text file available, even one of
the example C programs.
HOW DO WE PRINT?
-----------------------------------------------------------------
Load the last example program in this chapter, ================
the one named PRINTDAT.C for an example of how PRINTDAT.C
to print. This program should not present any ================
surprises to you so we will move very quickly
through it. Once again, we open TENLINES.TXT for reading and we
open PRN for writing. Printing is identical to writing data to a
disk file except that we use a standard name for the filename.
Most C compilers use the reserved filename of PRN that instructs
the compiler to send the output to the printer. There are other
names that are used occasionally such as LPT, LPT1, or LPT2.
Check the documentation for your particular compiler. Some of
the newest compilers use a predefined file pointer such as stdprn
for the print file. Once again, check your documentation.
The program is simply a loop in which a character is read, and if
it is not the EOF, it is displayed and printed. When the EOF is
found, the input file and the printer output files are both
closed. Note that good programming practice would include
checking both file pointers to assure that the files were opened
properly. You can now erase TENLINES.TXT from your disk. We
will not be using it in any of the later chapters.
PROGRAMMING EXERCISES
-----------------------------------------------------------------
1. Write a program that will prompt for a filename for an input
file, prompt for a filename for a write file, and open both
plus a file to the printer. Enter a loop that will read a
character, and output it to the file, the printer, and the
monitor. Stop at EOF.
2. Prompt for a filename to read. Read the file a line at a
time and display it on the monitor with line numbers.
3. Modify ANYFILE.C to test if the file exists and print a
message if it doesn't. Use a method similar to that used in
READCHAR.C.
Page 10-7